package jp.dodododo.dao.util;

import java.util.Arrays;

/**
 * {@.en }
 * 
 * <br />
 * 
 * {@.ja }
 * 
 * @author Satoshi Kimura
 */
public abstract class EnumConverter {

	@SuppressWarnings("unchecked")
	public static Enum<?> convertToEnum(Object value, Class<?> dest) {
		Class enumClass = dest;
		return EnumConverter.convert(value, enumClass);
	}

	public static <E extends Enum<E>> E convert(Object value, Class<E> enumClass) {
		if (value == null) {
			return null;
		}
		E[] enumConstants = enumClass.getEnumConstants();
		if (NameKey.class.isAssignableFrom(enumClass)) {
			E val = nameToEnum(value, enumConstants);
			if (val != null) {
				return val;
			}
		} else if (OrdinalKey.class.isAssignableFrom(enumClass) && value instanceof Number) {
			return enumConstants[((Number) value).intValue()];
		} else if (StringKey.class.isAssignableFrom(enumClass)) {
			for (E e : enumConstants) {
				if (((StringKey) e).str().equals(value.toString())) {
					return e;
				}
			}
		} else if (NumKey.class.isAssignableFrom(enumClass) && value instanceof Number) {
			for (E e : enumConstants) {
				if (((NumKey) e).num() == ((Number) value).doubleValue()) {
					return e;
				}
			}
		} else if (value instanceof CharSequence) {
			E val = nameToEnum(value, enumConstants);
			if (val != null) {
				return val;
			}
		} else if (value instanceof Number) {
			int index = ((Number) value).intValue();
			if (0 <= index && index < enumConstants.length) {
				return enumConstants[index];
			}
		}
		throw new IllegalArgumentException("value=[" + value + "] enumClass=[" + enumClass + "(" + Arrays.asList(enumConstants) + ")]");
	}

	private static <E extends Enum<E>> E nameToEnum(Object value, E[] enumConstants) {
		for (E e : enumConstants) {
			if (e.name().equals(value.toString())) {
				return e;
			}
		}
		return null;
	}

	public static interface NameKey {
		String name();
	}

	public static interface OrdinalKey {
		int ordinal();
	}

	public static interface StringKey {
		String str();
	}

	public static interface NumKey {
		double num();
	}

}
